import cv2 as cv
import numpy as np

def reorder(myPoints):
    myPoints = myPoints.reshape((4, 2))
    myPointsNew = np.zeros((4, 1, 2), dtype=np.int32)
    add = myPoints.sum(1)

    myPointsNew[0] = myPoints[np.argmin(add)]
    myPointsNew[3] = myPoints[np.argmax(add)]
    diff = np.diff(myPoints, axis=1)
    myPointsNew[1] = myPoints[np.argmin(diff)]
    myPointsNew[2] = myPoints[np.argmax(diff)]

    return myPointsNew

def pre_process(img):
    blur_size = 5
    img_blur = cv.GaussianBlur(img, (blur_size, blur_size), 0)
    cv.imshow("blur", img_blur)
    # cv.waitKey(0)

    img_gray = cv.cvtColor(img_blur, cv.COLOR_BGR2GRAY)
    cv.imshow("gray", img_gray)
    # cv.waitKey(0)

    kernal = np.ones((10, 10), np.uint8)
    img_opening = cv.morphologyEx(img_gray, cv.MORPH_OPEN, kernal)
    cv.imshow("opening", img_opening)
    # cv.waitKey(0)

    img_opening = cv.addWeighted(img_gray, 1, img_opening, -1, 0)
    cv.imshow("merged", img_opening)
    # cv.waitKey(0)

    ret, img_thresh = cv.threshold(img_opening, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
    img_edge = cv.Canny(img_thresh, 100, 200)
    cv.imshow("edged", img_edge)
    # cv.waitKey(0)

    Matrix = np.ones((4, 19), np.uint8)
    img_edge1 = cv.morphologyEx(img_edge, cv.MORPH_CLOSE, Matrix)
    cv.imshow("edged1", img_edge1)

    img_edge2 = cv.morphologyEx(img_edge1, cv.MORPH_OPEN, Matrix)
    cv.imshow("edged2", img_edge2)
    # cv.waitKey(0)
    return img_edge2

def pre_process2(img):
    img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
    min = np.array([103, 173, 96])
    max = np.array([132, 255, 255])
    img_mask = cv.inRange(img_hsv, min, max)
    cv.imshow("mask", img_mask)
    cv.waitKey(0)
    kernal = np.ones((10, 10), np.uint8)
    img_mask = cv.morphologyEx(img_mask, cv.MORPH_CLOSE, kernal)
    cv.imshow("mask", img_mask)
    cv.waitKey(0)
    #imgWithMask = cv.bitwise_and(img, img, mask=img_mask)
    return img_mask

def find_targets(img_bin):
    Min_Area = 1000
    Max_Area = 10000
    contours, hierarchy = cv.findContours(img_bin, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    print("contours:", len(contours))

    # 剔除面积不在有效范围内的轮廓
    contours = [cnt for cnt in contours if Max_Area> cv.contourArea(cnt) > Min_Area]
    target_rects = []
    for cnt in contours:
        # 找到能围住此轮廓的最小矩形 minRect, 它是一个三元组 ((中心点X，中心点Y), (宽度, 高度)，矩形的旋转角度)
        minRect = cv.minAreaRect(cnt)

        #剔除角度不在有效范围内的轮廓
        if -100<minRect[2]<-80:
            height, width = minRect[1]
            if width < height:
                width, height = height, width
            ratio = width / height
            #剔除宽高比不在有效范围内的轮廓
            if 2 < ratio < 6:
                print(ratio, minRect[2])
                target_rects.append(minRect)
    return target_rects
def deskew(img):
    img_color= img.copy()
    h, w = img.shape[:2]
    img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    m = cv.moments(img)
    if abs(m['mu02']) < 1e-2:
        return img_color.copy()
    skew = m['mu11']/m['mu02']*(-2)
    M = np.float32([[1, skew, -0.5*w*skew], [0, 1, 0]])
    img = cv.warpAffine(img_color,M,(w, h),flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
    return img

def fetch_target(target_rects):
    target_imgs = []
    for rect in target_rects:
        # boxPoints是把中心点，长宽角度转换成四个角点坐标
        # rect = (rect[0], (rect[1][0]+10, rect[1][1]+10), rect[2])
        M = cv.getRotationMatrix2D(rect[0], rect[2] + 90, 1)
        dst = cv.warpAffine(img, M, (img_width, img_hight))
        cv.imshow("warpAffine", dst)
        cv.waitKey(0)
        center_x, center_y = np.int0(rect[0])
        # print("center:",center_x, center_y)

        width, height = np.int0(rect[1])
        if width < height:
            width, height = height, width
        print("width height :", width, height )
        print("rect:", center_y - (height//2) ,center_y + (height//2), center_x - (width//2) , center_x + (width//2))
        extend_size = 10
        try:
            target_img = dst[center_y - (height // 2) - extend_size: center_y + (height // 2) + extend_size,
                         center_x - (width // 2) - extend_size: center_x + (width // 2) + extend_size]
            target_img = deskew(target_img)
            target_imgs.append(target_img)
            cv.imshow("targets", target_img)
            cv.waitKey(0)

        except:
            pass
    return target_rects
        # box_points = cv.boxPoints(rect)
        # box_points = np.int0(box_points)
        # #cv.drawContours(img, [box_points], -1, (0, 0, 255), 3)
        #
        # left_top, right_top, left_bottom, right_bottom= np.reshape(reorder(box_points), (4,2))
        # print("box_points", box_points)
        # print('corners', left_top, right_top, left_bottom, right_bottom)
        #
        # pts1 = np.float32([left_top, right_top, right_bottom])
        # pts2 = np.float32([left_top, (right_top[0], left_top[1]), (right_top[0], right_bottom[1])])
        # print(pts1, pts2)
        # M = cv.getAffineTransform(pts1, pts2)
        # dst = cv.warpAffine(oldimg, M, (pic_width, pic_hight))
        # target_img = dst[left_top[1]: right_bottom[1], left_top[0]: right_top[0]]
        # target_imgs.append(target_img)
        # cv.imshow("targets", target_img)
        # cv.waitKey(0)

img = cv.imread('assets/car2.jpg')
img_hight, img_width = img.shape[:2]
img_bin = pre_process2(img)
target_rects = find_targets(img_bin)
print( "找到的目标区域数：", len(target_rects))
img_targets = fetch_target(target_rects)
print(len(img_targets))



